package ssh

import (
	"fmt"
	"github.com/pkg/sftp"
	"golang.org/x/crypto/ssh"
	"kubeInstall/utils"
	"kubeInstall/utils/file"
	"net"
	"os"
	"strconv"
	"time"
)

func (ss *SSH) sshAuthMethod(passwd, pkFile string) ssh.AuthMethod {
	var am ssh.AuthMethod
	if passwd != "" {
		am = ssh.Password(passwd)
	} else {
		pkData := file.ReadFile(pkFile)
		pk, err := ssh.ParsePrivateKey([]byte(pkData))
		if err != nil {
			utils.Error(err)
			os.Exit(1)
		}
		am = ssh.PublicKeys(pk)
	}
	return am
}

func (ss *SSH) addrReformat(hostIp string, port int) string {

	if port == 0 {
		return fmt.Sprintf("%s:22", hostIp)
	}
	strPort := strconv.Itoa(port)
	return fmt.Sprintf("%s:%s", hostIp, strPort)
}

func (ss *SSH) connect() (*ssh.Client, error) {
	auth := []ssh.AuthMethod{ss.sshAuthMethod(ss.Password, ss.PkFile)}
	config := ssh.Config{
		Ciphers: []string{"aes128-ctr", "aes192-ctr", "aes256-ctr", "aes128-gcm@openssh.com", "arcfour256", "arcfour128", "aes128-cbc", "3des-cbc", "aes192-cbc", "aes256-cbc"},
	}
	DefaultTimeout := time.Duration(1) * time.Minute
	if ss.Timeout == nil {
		ss.Timeout = &DefaultTimeout
	}
	clientConfig := &ssh.ClientConfig{
		User:    ss.User,
		Auth:    auth,
		Timeout: *ss.Timeout,
		Config:  config,
		HostKeyCallback: func(hostname string, remote net.Addr, key ssh.PublicKey) error {
			return nil
		},
	}

	addr := ss.addrReformat(ss.HostIp, ss.Port)
	return ssh.Dial("tcp", addr, clientConfig)
}
func (ss *SSH) SshInit() error {
	var (
		sshClient  *ssh.Client
		sftpClient *sftp.Client
		err        error
	)

	if sshClient, err = ss.connect(); err != nil {
		return err
	}

	if sftpClient, err = sftp.NewClient(sshClient); err != nil {
		return err
	}

	ss.SshClient = sshClient
	ss.SftpClient = sftpClient

	return nil
}

func (ss *SSH) NewSession() (*ssh.Session, error) {
	session, err := ss.SshClient.NewSession()
	if err != nil {
		return nil, err
	}

	modes := ssh.TerminalModes{
		ssh.ECHO:          0,     // disable echoing
		ssh.TTY_OP_ISPEED: 14400, // input speed = 14.4kbaud
		ssh.TTY_OP_OSPEED: 14400, // output speed = 14.4kbaud
	}

	if err := session.RequestPty("xterm", 80, 40, modes); err != nil {
		return nil, err
	}

	return session, nil
}
